package com.five.filesync;

import android.content.Context;
import android.content.Intent;
import android.net.DhcpInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.regex.Pattern;

public class UdpBroadCastUtils {
    private static final String TAG = "BroadcastUtils";
    private static final int BROADCAST_PORT = 8990;

    public static class RespondData {
        public InetAddress addr;
        public String respond;

        @Override
        public String toString() {
            return "RespondData{" +
                    "addr=" + addr +
                    ", respond='" + respond + '\'' +
                    '}';
        }
    }

    public static RespondData sendBroadcastAndReceiveReply(Context context, String msg) {
        try {
            DatagramSocket socket = new DatagramSocket();
            socket.setBroadcast(true);

            // 发送广播消息到 8990 端口
            byte[] sendData = msg.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(context), BROADCAST_PORT);
            socket.send(sendPacket);

            // 接收对端回复
            byte[] receiveData = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.setSoTimeout(2000); // 设置超时时间
            try {
                socket.receive(receivePacket);
            } catch (SocketTimeoutException socketTimeoutException) {
                Log.e(TAG, "receive timeout");
                return new RespondData();
            }
            String replyMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());

            socket.close();

            RespondData ret = new RespondData();
            ret.respond = replyMessage;
            ret.addr = receivePacket.getAddress();
            return ret;
        } catch (IOException e) {
            Log.e(TAG, "Error sending/receiving broadcast", e);
        }

        return null;
    }

    private static InetAddress getBroadcastAddress(Context context) throws IOException {
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();

        byte[] a = intToBytes2(dhcpInfo.ipAddress);

        int netmask = getIpAddrMask();
        byte[] c = intToBytes2(netmask);

//        Log.d("dns", String.format("%32s", Integer.toBinaryString(dhcpInfo.ipAddress)));
//        Log.d("dns", String.format("%32s", Integer.toBinaryString(netmask)));
        int broadcast = (dhcpInfo.ipAddress & netmask) | ~netmask;
//        Log.d("dns", String.format("%32s", Integer.toBinaryString(broadcast)));
        byte[] broadcastBytes = new byte[4];
        for (int i = 0; i < 4; i++) {
            broadcastBytes[i] = (byte) ((broadcast >> (i * 8)) & 0xFF);
        }

        try {
            InetAddress address = InetAddress.getByAddress(broadcastBytes);
            return address;
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static int getIpAddrMask() {
        try {
            Enumeration<NetworkInterface> networkInterfaceEnumeration = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaceEnumeration.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaceEnumeration.nextElement();
                if (!networkInterface.isUp()) {
                    continue;
                }
                for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
                    if (interfaceAddress.getAddress() instanceof Inet4Address) {
                        if (!"127.0.0.1".equals(interfaceAddress.getAddress().getHostAddress())) {
                            return calNetmaskByLen(interfaceAddress.getNetworkPrefixLength());
                        }
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static int calNetmaskByLen(int len) {
//        int mask = 0xffffffff << (32 - len);
        return bigEndianToLittleEndian(0xffffffff << (32 - len));
    }



    public static String calcMaskByPrefixLength(int length) {
        int mask = 0xffffffff << (32 - length);
        int partsNum = 4;
        int bitsOfPart = 8;
        int[] maskParts = new int[partsNum];
        int selector = 0x000000ff;

        for (int i = 0; i < maskParts.length; i++) {
            int pos = maskParts.length - 1 - i;
            maskParts[pos] = (mask >> (i * bitsOfPart)) & selector;
        }

        String result = "";
        result = result + maskParts[0];
        for (int i = 1; i < maskParts.length; i++) {
            result = result + "." + maskParts[i];
        }
        return result;
    }

    private static int bigEndianToLittleEndian(int v) {
        return ((v & 0xFF) << 24) |
                ((v & 0xFF00) << 8) |
                ((v >> 8) & 0xFF00) |
                ((v >> 24) & 0xFF);
    }

    private static byte[] intToBytes2(int n){
        byte[] b = new byte[4];
        for(int i = 0;i < 4;i++){
            b[i] = (byte)(n >> (24 - i * 8));
        }
        return b;
    }
}